package com.fessc.develop.handler.processor.request;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fessc.develop.base.Result;
import com.fessc.develop.entity.comvo.CheckAccumulate;
import com.fessc.develop.entity.dbvo.SettleTrade;
import com.fessc.develop.entity.dbvo.TPayment;
import com.fessc.develop.entity.ApplicationPropertiesVo;
import com.fessc.develop.entity.comvo.CheckBodyVo;
import com.fessc.develop.model.enums.EnumJsonProperty;
import com.fessc.develop.model.enums.EnumPaymentStatus;
import com.fessc.develop.model.enums.EnumResultType;
import com.fessc.develop.model.enums.EnumServiceCode;
import com.fessc.develop.service.interfaces.ISettleTradeService;
import com.fessc.develop.service.interfaces.ITPaymentService;
import com.fessc.develop.utils.BusiUtil;
import com.fessc.develop.utils.DateUtil;
import com.fessc.develop.utils.ExceptionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;

@Slf4j
@Service
public class ComCheckingProcess implements IBaseService {

    @Resource
    private ITPaymentService paymentService;

    @Resource
    private ISettleTradeService settleTradeService;

    @Resource(name = "AsyncThreadExecutor")
    private ThreadPoolTaskExecutor taskExecutor;

    @Resource
    private ApplicationPropertiesVo propertiesVo;


    @Override
    public String getServiceCode() {
        return EnumServiceCode.PLAT_CHECK.toString();
    }

    @Override
    public Result process(JSONObject request) {
        CheckBodyVo checkingVo = JSON.parseObject(request.getJSONObject(EnumJsonProperty.REQ_BODY.toString()).toJSONString(), CheckBodyVo.class);
        log.info(checkingVo.getChannel() + " 渠道发起对账，对账日期：" + checkingVo.getCheckingDate());
        Result result = null;
        String fileName = getFileName(checkingVo);
        //异步生成文件
        taskExecutor.submit(new Runnable() {
            @Override
            public void run() {
                switch (checkingVo.getCheckingType()) {
                    case "1":
                        //生成预付款对账文件
                        generatePrePaymentCheckingFile(fileName, checkingVo);
                        break;
                    case "2":
                        //生成预付款退款对账文件
                        generateRefundCheckingFile(fileName, checkingVo);
                        break;
                    case "3":
                        //生成跨境付汇对账文件
                        generateSettleTradeCheckingFile(fileName, checkingVo);
                        break;
                    default:
                        throw ExceptionUtil.businessException("EE4015");
                }
            }
        });

        result = new Result(EnumResultType.SUCCESS.getStatusCode(), EnumResultType.SUCCESS.getMsg());
        return result;
    }

    private void generatePrePaymentCheckingFile(String fileName, CheckBodyVo checkingVo) {
        log.info("生成预付款对账文件开始： " + fileName);
        String okFileName = fileName + ".ok";
        FileOutputStream fos = null;
        PrintWriter pw = null;
        File fileData = new File(fileName);

        List<TPayment> paymentList = paymentService.getPrePaymentCheckingList(checkingVo.getCheckingDate(), checkingVo.getChannel());
        try {
            fos = new FileOutputStream(fileData);
            pw = new PrintWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8), true);
            CheckAccumulate accumulate = new CheckAccumulate();
            for (TPayment tPayment : paymentList) {

                //付款成功
                if (BusiUtil.isEquals(tPayment.getPaymentStatus(), EnumPaymentStatus.PAYMENT_SUCCESS.toString())) {
                    accumulate.totalSucAmtAccumulate(tPayment.getTotalAmount());
                    accumulate.totalSucNumAccumulate();
                } else if (BusiUtil.isEquals(tPayment.getPaymentStatus(), EnumPaymentStatus.SEND.toString())) {
                    accumulate.totalFailAmtAccumulate(tPayment.getTotalAmount());
                    accumulate.totalFailNumAccumulate();
                }
                accumulate.totalAmtAccumulate(tPayment.getTotalAmount());
                accumulate.totalNumAccumulate();

                pw.write(tPayment.getPaymentRefids());
                pw.write("\033");
                pw.write(tPayment.getSuborderno());
                pw.write("\033");
                pw.write(tPayment.getBankRefids());
                pw.write("\033");
                pw.write(tPayment.getPayerbankcode());
                pw.write("\033");
                pw.write(tPayment.getPayeraccountnumber());
                pw.write("\033");
                pw.write(tPayment.getPayeraccountname());
                pw.write("\033");
                pw.write(tPayment.getPayeeBankNo());
                pw.write("\033");
                pw.write(tPayment.getPayeeaccountnumber());
                pw.write("\033");
                pw.write(tPayment.getPayeeaccountname());
                pw.write("\033");
                pw.write(tPayment.getTotalAmount().toString());
                pw.write("\033");
                pw.write(tPayment.getPaymentStatus());
                pw.write("\033");
                if (BusiUtil.isEquals(tPayment.getPaymentStatus(), EnumPaymentStatus.SEND.toString())
                        && BusiUtil.isNull(tPayment.getPaymentLog())) {
                    pw.write("银行尚未返回结果");
                } else {
                    pw.write(tPayment.getPaymentLog());
                }
                pw.println();
            }
            pw.flush();
            //写入ok文件/
            generateOkFile(okFileName, accumulate);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (fos !=null ) {
                    fos.close();
                }
            } catch (Exception e) {
                log.info("关闭文件输出流异常： " + e.getMessage());
            }
            try {
                if (pw !=null ) {
                    pw.close();
                }
            } catch (Exception e) {
                log.info("关闭文本输出流异常： " + e.getMessage());
            }
        }
        log.info("生成预付款对账文件结束： " + fileName);
    }

    private void generateRefundCheckingFile(String fileName, CheckBodyVo checkingVo) {
        log.info("生成预付款退款对账文件开始： " + fileName);
        String okFileName = fileName + ".ok";
        FileOutputStream fos = null;
        PrintWriter pw = null;
        File fileData = new File(fileName);
        File okData = new File(okFileName);
        List<TPayment> paymentList = paymentService.getRefundCheckingList(checkingVo.getCheckingDate(), checkingVo.getChannel());
        try {
            fos = new FileOutputStream(fileData);
            pw = new PrintWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8), true);
            CheckAccumulate accumulate = new CheckAccumulate();
            for (TPayment tPayment : paymentList) {

                //付款成功
                if (BusiUtil.isEquals(tPayment.getPaymentStatus(), EnumPaymentStatus.PAYMENT_SUCCESS.toString())) {
                    accumulate.totalSucAmtAccumulate(tPayment.getTotalAmount());
                    accumulate.totalSucNumAccumulate();
                } else if (BusiUtil.isEquals(tPayment.getPaymentStatus(), EnumPaymentStatus.SEND.toString())) {
                    accumulate.totalFailAmtAccumulate(tPayment.getTotalAmount());
                    accumulate.totalFailNumAccumulate();
                }
                accumulate.totalAmtAccumulate(tPayment.getTotalAmount());
                accumulate.totalNumAccumulate();

                pw.write(tPayment.getPaymentRefids());
                pw.write("\033");
                pw.write(tPayment.getSuborderno());
                pw.write("\033");
                pw.write(tPayment.getRefundRefids());
                pw.write("\033");
                pw.write(tPayment.getPayerbankcode());
                pw.write("\033");
                pw.write(tPayment.getPayeraccountnumber());
                pw.write("\033");
                pw.write(tPayment.getPayeraccountname());
                pw.write("\033");
                pw.write(tPayment.getPayeeBankNo());
                pw.write("\033");
                pw.write(tPayment.getPayeeaccountnumber());
                pw.write("\033");
                pw.write(tPayment.getPayeeaccountname());
                pw.write("\033");
                pw.write(tPayment.getTotalAmount().toString());
                pw.write("\033");
                pw.write(tPayment.getRefundStatus());
                pw.write("\033");
                if (BusiUtil.isEquals(tPayment.getVerifyStatus(), "Y") && BusiUtil.isNull(tPayment.getRefundStatus())) {
                    pw.write("银行尚未返回结果");
                } else {
                    pw.write(tPayment.getPaymentLog());
                }
                pw.println();
            }
            pw.flush();
            //写入ok文件
            generateOkFile(okFileName, accumulate);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (fos !=null ) {
                    fos.close();
                }
            } catch (Exception e) {
                log.info("关闭文件输出流异常： " + e.getMessage());
            }
            try {
                if (pw !=null ) {
                    pw.close();
                }
            } catch (Exception e) {
                log.info("关闭文本输出流异常： " + e.getMessage());
            }
        }
        log.info("生成预付款退款对账文件结束： " + fileName);
    }

    private void generateSettleTradeCheckingFile(String fileName, CheckBodyVo checkingVo) {
        log.info("生成跨境付汇对账文件开始： " + fileName);
        String okFileName = fileName + ".ok";
        FileOutputStream fos = null;
        PrintWriter pw = null;
        File fileData = new File(fileName);
        File okData = new File(okFileName);
        List<SettleTrade> settleTrades = settleTradeService.getSettleTradeCheckingList(checkingVo.getCheckingDate(), checkingVo.getChannel());
        try {
            fos = new FileOutputStream(fileData);
            pw = new PrintWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8), true);
            CheckAccumulate accumulate = new CheckAccumulate();
            for (SettleTrade settleTrade : settleTrades) {

                //付款成功
                if (BusiUtil.isEquals(settleTrade.getReviewStatus(), "2")) {
                    accumulate.totalSucAmtAccumulate(settleTrade.getAmount());
                    accumulate.totalSucNumAccumulate();
                } else if (BusiUtil.isEquals(settleTrade.getPaymentTypeSend(), "Y") && BusiUtil.isEquals(settleTrade.getReviewStatus(), "3")) {
                    accumulate.totalFailAmtAccumulate(settleTrade.getAmount());
                    accumulate.totalFailNumAccumulate();
                }
                accumulate.totalAmtAccumulate(settleTrade.getAmount());
                accumulate.totalNumAccumulate();

                pw.write(settleTrade.getSettleId());
                pw.write("\033");
                pw.write(settleTrade.getOrderno());
                pw.write("\033");
                pw.write(settleTrade.getSerialnumber());
                pw.write("\033");
                pw.write(settleTrade.getOrgCode());
                pw.write("\033");
                pw.write(settleTrade.getAmount().toString());
                pw.write("\033");
                pw.write(settleTrade.getReviewStatus());
                pw.println();
            }
            pw.flush();
            //写入ok文件
            generateOkFile(okFileName, accumulate);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (fos !=null ) {
                    fos.close();
                }
            } catch (Exception e) {
                log.info("关闭文件输出流异常： " + e.getMessage());
            }
            try {
                if (pw !=null ) {
                    pw.close();
                }
            } catch (Exception e) {
                log.info("关闭文件输出流异常： " + e.getMessage());
            }
        }
        log.info("生成跨境付汇对账文件结束： " + fileName);
    }

    private void generateOkFile(String okFile, CheckAccumulate accumulate) throws Exception {
        FileOutputStream fos =  null;
        PrintWriter pw = null;
        try {
            File okData = new File(okFile);
            fos = new FileOutputStream(okData);
            pw = new PrintWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8), true);
            pw.write(accumulate.getTotalNum() + "");
            pw.println();
            pw.write(accumulate.getTotalAmt().toString());
            pw.println();
            pw.write(accumulate.getTotalSucNum());
            pw.println();
            pw.write(accumulate.getTotalSucAmt().toString());
            pw.println();
            pw.write(accumulate.getTotalFailNum());
            pw.println();
            pw.write(accumulate.getTotalFailAmt().toString());
            pw.println();
            pw.flush();
        } catch (Exception e) {
            log.info("生成对账文件异常： " + e.getMessage());
        } finally {
            try {
                if (fos !=null ) {
                    fos.close();
                }
            } catch (Exception e) {
                log.info("关闭文件输出流异常： " + e.getMessage());
            }
            try {
                if (pw !=null ) {
                    pw.close();
                }
            } catch (Exception e) {
                log.info("关闭文件输出流异常： " + e.getMessage());
            }
        }
    }

    private String getFileName(CheckBodyVo checkingVo) {
        log.info("文件保存路径：" + propertiesVo.getAppCheckFilePath());
        String fileName = propertiesVo.getAppCheckFilePath() + DateUtil.getCurrentDate() + checkingVo.getChannel() + "_" + checkingVo.getCheckingDate();
        switch (checkingVo.getCheckingType()) {
            case "1":
                //生成预付款对账文件
                fileName = fileName + "_prepayment.txt";
                break;
            case "2":
                //生成预付款退款对账文件
                fileName = fileName + "_refund.txt";
                break;
            case "3":
                //生成跨境付汇对账文件
                fileName = fileName + "_crossborder.txt";
                break;
            default:
                throw ExceptionUtil.businessException("EE4015");
        }
        return fileName;
    }
}
